home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / info-service / www / src / midaswww-1.0 / midasevaluate.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-11-16  |  10.9 KB  |  367 lines

  1. #include <Mrm/MrmAppl.h>                        /* Motif Toolkit and MRM */
  2. #include "midasoperand.h"
  3. #include <string.h>
  4.  
  5. extern Widget ActiveWidget;
  6. MidasOperand MidasGetIngotValue();
  7. MidasOperand MidasCallFunction();
  8. XtPointer MidasFindIngot();
  9.  
  10. static char *UnaryOperatorCharacters = "+-";
  11. static char *BinaryOperatorCharacters = "+-*/><!=&|";
  12.  
  13. static MidasOperator BinaryOperators[] = {
  14.                                 {"==", 6,  MString,  MString, MBoolean},
  15.                                 {"!=", 6,  MString,  MString, MBoolean},
  16.                                 {"<=", 7,  MNumber,  MNumber, MBoolean},
  17.                                 {">=", 7,  MNumber,  MNumber, MBoolean},
  18.                                 {"&&", 1, MBoolean, MBoolean, MBoolean},
  19.                                 {"||", 1, MBoolean, MBoolean, MBoolean}, 
  20.                                 {"//", 9,     MInt,     MInt,     MInt},
  21.                                 {"++",10,  MString,  MString,  MString}, 
  22.                                 {"<" , 7,  MNumber,  MNumber, MBoolean},
  23.                                 {">" , 7,  MNumber,  MNumber, MBoolean},
  24.                                 {"+" , 8,  MNumber,  MNumber,  MNumber},
  25.                                 {"-" , 8,  MNumber,  MNumber,  MNumber},
  26.                                 {"*" , 9,  MNumber,  MNumber,  MNumber},
  27.                                 {"/" , 9,  MNumber,  MNumber,  MNumber}};
  28.  
  29. static char *SBool[2] = {"False" , "True"};
  30.  
  31. MidasOperand MidasApplyOperation(Op1,Op2,Op)
  32.   MidasOperand  Op1; 
  33.   MidasOperand  Op2; 
  34.   MidasOperator *Op;
  35. {
  36.   MidasOperand Result;
  37.   Boolean Float = FALSE;
  38.   int v1,v2,v;
  39.   float f;
  40.  
  41.   Result.Dynamic = FALSE;
  42.  
  43.   if (strcmp(Op1.Type,Op->Op1)) MidasConvertOperand(&Op1,Op->Op1);    
  44.   if (strcmp(Op2.Type,Op->Op2)) MidasConvertOperand(&Op2,Op->Op2);
  45.  
  46.   if (strcmp(Op->Op1,MNumber) == 0)
  47.     { 
  48.       if      (strcmp(Op1.Type,MFloat) == 0) Float = TRUE;
  49.       else if (strcmp(Op2.Type,MFloat) == 0) Float = TRUE;
  50.  
  51.       if (Float && strcmp(Op1.Type,MFloat)) MidasConvertOperand(&Op1,MFloat);    
  52.       if (Float && strcmp(Op2.Type,MFloat)) MidasConvertOperand(&Op2,MFloat);
  53.     }
  54.  
  55.   v1 = Op1.Value.I;
  56.   v2 = Op2.Value.I;
  57.  
  58.   if      (strcmp(Op->Symbol,"==") == 0) v = strcmp((char *)v1,(char *)v2) == 0; 
  59.   else if (strcmp(Op->Symbol,"!=") == 0) v = strcmp((char *)v1,(char *)v2) != 0; 
  60.   else if (strcmp(Op->Symbol,"&&") == 0) v =  v1 ?   v2 : FALSE; 
  61.   else if (strcmp(Op->Symbol,"||") == 0) v =  v1 ? TRUE :  v2; 
  62.   else if (strcmp(Op->Symbol,"++") == 0) 
  63.     {
  64.       v = (int) XtMalloc(strlen((char *)v1)+strlen((char *)v2)+1);
  65.       strcpy((char *)v,(char *)v1);
  66.       strcat((char *)v,(char *)v2);
  67.       Result.Dynamic = TRUE;
  68.     } 
  69.   else if (strcmp(Op->Symbol,"//") == 0) 
  70.     {
  71.       if ( v2 == 0) MidasError("Integer division by zero"); 
  72.       v =  v1 /  v2;
  73.     }
  74.   else if (Float)
  75.     {
  76.       float f1 = Op1.Value.F;
  77.       float f2 = Op2.Value.F;
  78.  
  79.       if      (strcmp(Op->Symbol,">=") == 0) f =  f1 >=  f2; 
  80.       else if (strcmp(Op->Symbol,"<=") == 0) f =  f1 <=  f2; 
  81.       else if (strcmp(Op->Symbol,">" ) == 0) f =  f1 >   f2; 
  82.       else if (strcmp(Op->Symbol,"<" ) == 0) f =  f1 <   f2; 
  83.       else if (strcmp(Op->Symbol,"-")  == 0) f =  f1 -   f2;
  84.       else if (strcmp(Op->Symbol,"+")  == 0) f =  f1 +   f2;
  85.       else if (strcmp(Op->Symbol,"*")  == 0) f =  f1 *   f2;
  86.       else if (strcmp(Op->Symbol,"/")  == 0) 
  87.         {
  88.           if (f2 == 0) MidasError("Division by zero"); 
  89.           f = f1 / f2;
  90.         }
  91.       else MidasError("Midas Internal Error: MidasApplyOperation");
  92.     }
  93.   else
  94.     {
  95.       if      (strcmp(Op->Symbol,">=") == 0) v =  v1 >=  v2; 
  96.       else if (strcmp(Op->Symbol,"<=") == 0) v =  v1 <=  v2; 
  97.       else if (strcmp(Op->Symbol,">" ) == 0) v =  v1 >   v2; 
  98.       else if (strcmp(Op->Symbol,"<" ) == 0) v =  v1 <   v2; 
  99.       else if (strcmp(Op->Symbol,"-")  == 0) v =  v1 -   v2;
  100.       else if (strcmp(Op->Symbol,"+")  == 0) v =  v1 +   v2;
  101.       else if (strcmp(Op->Symbol,"*")  == 0) v =  v1 *   v2;
  102.       else if (strcmp(Op->Symbol,"/")  == 0) 
  103.         {
  104.           float r;
  105.           if (v2 == 0) MidasError("Division by zero"); 
  106.           if (v1 % v2 == 0) v = v1 / v2;
  107.           else
  108.             {
  109.               f = (float) v1 / (float) v2;
  110.               Float = TRUE;
  111.             }
  112.         }
  113.       else MidasError("Midas Internal Error: MidasApplyOperation");
  114.     }
  115.  
  116.   if (Op1.Dynamic) XtFree((char *)Op1.Value.P);
  117.   if (Op2.Dynamic) XtFree((char *)Op2.Value.P); 
  118.  
  119.   if (Float) Result.Value.F = f;
  120.   else       Result.Value.I = v;
  121.  
  122.   if (strcmp(Op->Result,MNumber) == 0) Result.Type = Float ? MFloat : MInt;
  123.   else Result.Type = Op->Result;
  124.  
  125.   return Result; 
  126. }
  127. static MidasOperand MidasEvaluateFunction(in,outlen)
  128. char *in;
  129. int *outlen;
  130. {
  131.   MidasOperand Temp;
  132.   char *q = in;
  133.  
  134.   Temp = MidasCallFunction(&q);
  135.   *outlen = q - in + 1;
  136.   return Temp;
  137. }
  138. MidasOperand MidasEvaluateExpression(in)
  139. char *in;
  140. {
  141.    MidasStack Stack[10];
  142.    MidasStack *SP = &Stack[0];
  143.    MidasOperator Dummy, EndOfLine, *CurrentOperator;   
  144.    char Unary = '\0';
  145.  
  146. #ifdef debug
  147.    printf("Evaluating: %s\n",in);
  148. #endif
  149.  
  150.    Dummy.Precedence = -1;
  151.    EndOfLine.Precedence = 0;
  152.    EndOfLine.Symbol = "";
  153.    SP->Op = &Dummy; 
  154.  
  155.    for (;;)
  156.      {
  157.        int l1;
  158.        if (*in != '\0' && strchr(UnaryOperatorCharacters,*in) != 0) Unary = *in++;
  159. /*
  160.        Tokens in expressions may be:
  161.  
  162.           a) sub-expressions (in parentheses)
  163.           b) Function invokations
  164.           c) Quoted strings
  165.           d) Ingots
  166.           e) Unquoted strings
  167.  
  168.        First deal with Sub-expressions 
  169. */
  170.        if (*in == '(')
  171.          {
  172.            int n = 1, q = 0;
  173.            char *p = in + 1;
  174.            for (; *p != '\0'; p++) 
  175.              {
  176.                if (*p == '"') q = !q;
  177.                else if (!q && *p == '(') n++;
  178.                else if (!q && *p == ')') if (--n == 0) break;
  179.              }    
  180.            if (q != 0) MidasError("Mismatched quotes in expression: %s",in);
  181.            if (n != 0) MidasError("Parenthesis error in expression: %s",in);
  182.            *p = '\0';
  183.            in++;
  184.            SP->Operand = MidasEvaluateExpression(in); 
  185.            l1 = p - in + 1;
  186.          } 
  187. /*
  188.        Now deal with quoted strings
  189. */
  190.        else if (*in == '"')
  191.          {
  192.            int q = 1;
  193.            char *p = in + 1;
  194.            for (; *p != '\0'; p++) if (*p == '"') { q = 0;  break; }
  195.            if (q != 0) MidasError("Mismatched quotes in expression: %s",in);
  196.            *p = '\0';
  197.            in++;
  198.            SP->Operand.Type = MString;
  199.            SP->Operand.Dynamic = FALSE;
  200.            SP->Operand.Value.P = (XtPointer) in; 
  201.            l1 = p - in + 1;
  202.          } 
  203.        else
  204. /*
  205.        Could be a function invokation
  206. */
  207.          {
  208.            char *l2 = strchr(in,'(');
  209.            l1 = strcspn(in,BinaryOperatorCharacters); 
  210.            if (l2 != NULL && l2 < in+l1) 
  211.              {
  212.                SP->Operand = MidasEvaluateFunction(in,&l1);
  213.              }
  214.            else 
  215.              {
  216. /*
  217.        Or it could be an ingot             
  218. */ 
  219.                XtPointer Ingot;               
  220.                char temp = *(in + l1);
  221.                *(in + l1) = '\0';
  222.  
  223.                Ingot = MidasFindIngot(ActiveWidget,in);
  224.                if (Ingot != 0) SP->Operand = MidasGetIngotValue(Ingot);
  225.                else 
  226.                  {
  227.                    SP->Operand.Type    = MString;
  228.                    SP->Operand.Dynamic = FALSE;
  229.                    SP->Operand.Value.P = (XtPointer) in;
  230.                  } 
  231.                *(in + l1) = temp;
  232.              }
  233.          }      
  234. /* 
  235.      Now deal with any pending unary operator
  236. */
  237.        if (Unary == '-') 
  238.          {
  239.            MidasConvertOperand(&SP->Operand,MInt);
  240.            SP->Operand.Value.I = -(int) SP->Operand.Value.I;
  241.          }
  242.  
  243.        if (*(in+l1) == '\0') CurrentOperator = &EndOfLine;
  244.        else
  245.          {
  246.            int op; 
  247.            for (op = 0;  op < XtNumber(BinaryOperators);  op++)
  248.                if (strncmp(in+l1,BinaryOperators[op].Symbol,
  249.                          strlen(BinaryOperators[op].Symbol)) == 0) break;
  250.  
  251.            if (op == XtNumber(BinaryOperators)) 
  252.              MidasError("Unrecognised operator %s in expression",in+l1);
  253.            CurrentOperator = &BinaryOperators[op];
  254.          }
  255.  
  256.        *(in+l1) = '\0';
  257.        in += l1 + strlen(CurrentOperator->Symbol);
  258.  
  259.        for (; CurrentOperator->Precedence <= SP->Op->Precedence; )
  260.          { 
  261.            (SP-1)->Operand = MidasApplyOperation((SP-1)->Operand,SP->Operand,SP->Op);
  262.            SP--;
  263.          }
  264.  
  265.        if (strcmp(CurrentOperator->Symbol,"&&") == 0)
  266.          { 
  267.            if (strcmp(SP->Operand.Type,MBoolean)) MidasConvertOperand(&SP->Operand,MBoolean);
  268.            if (SP->Operand.Value.I == FALSE) break; 
  269.          } 
  270.        else if (strcmp(CurrentOperator->Symbol,"||") == 0)
  271.          { 
  272.            if (strcmp(SP->Operand.Type,MBoolean)) MidasConvertOperand(&SP->Operand,MBoolean);
  273.            if (SP->Operand.Value.I == TRUE) break; 
  274.          } 
  275.  
  276.        if (CurrentOperator == &EndOfLine) break;
  277.        (++SP)->Op = CurrentOperator;
  278.     }       
  279. #ifdef debug
  280.   printf ("Result is %s = ",SP->Operand.Type);
  281.   if (strcmp(SP->Operand.Type,MString) == 0) printf("%s\n",SP->Operand.Value.I);
  282.   else                                       printf("%d\n",SP->Operand.Value.I); 
  283. #endif
  284.  
  285.   return SP->Operand; 
  286. }
  287. void MidasForceEvaluateExpression(in,out)
  288. char **in;
  289. char **out;
  290. {
  291.   MidasOperand Result;
  292.   char temp, *p = *in+1, *pp, *buffer;
  293.   int q = 0, m = 0;
  294.  
  295.   for (; *p != '\0' && *p != '\n'; p++)
  296.     {
  297.       if (*p == '"')
  298.         {
  299.           if (m == 0 && !q) break; 
  300.           else q = !q;
  301.         }
  302.       else if (!q && *p == '(') m++;
  303.       else if (!q && *p == ')') m--;
  304.       else if (!q && m == 0 && *p == ' ') break;
  305.     }
  306.     
  307.   temp = *p;
  308.   *p = '\0';
  309.   buffer = XtNewString(*in+1);
  310.   *p = temp;
  311.  
  312.   Result = MidasEvaluateExpression(buffer);
  313.   if (strcmp(Result.Type,MString) != 0) MidasConvertOperand(&Result,MString);
  314.       
  315.   for (pp = Result.Value.P; *pp != '\0';) *(*out)++ = *pp++;
  316.   if (Result.Dynamic) XtFree((char *)Result.Value.P);
  317.  
  318.   XtFree(buffer);
  319.   *in = p - 1;
  320. }
  321. int MidasConvertToInteger(Operand)
  322. MidasOperand Operand;
  323. {
  324.   if (strcmp(Operand.Type,MInt)) MidasConvertOperand(&Operand,MInt);
  325.   return Operand.Value.I;
  326. }
  327. char *MidasConvertToString(Operand)
  328. MidasOperand Operand;
  329. {
  330.   if (strcmp(Operand.Type,MString)) MidasConvertOperand(&Operand,MString);
  331.   return XtNewString(Operand.Value.P);
  332. }
  333. char *MidasConvertToBoolean(Operand)
  334. MidasOperand Operand;
  335. {
  336.   if (strcmp(Operand.Type,MBoolean)) MidasConvertOperand(&Operand,MString);
  337.   return Operand.Value.P;
  338. }
  339. MidasOperand MidasConvertFromString(string)
  340. char *string;
  341. {
  342.   MidasOperand Temp;
  343.   Temp.Type = MString;
  344.   Temp.Dynamic = TRUE;
  345.   Temp.Value.P = XtNewString(string);
  346.   return Temp;
  347. }
  348. MidasOperand MidasConvertFromInteger(i)
  349. int i;
  350. {
  351.   MidasOperand Temp;
  352.   Temp.Type = MInt;
  353.   Temp.Dynamic = FALSE;
  354.   Temp.Value.I = i;
  355.   return Temp;
  356. }
  357. MidasOperand MidasConvertFromBoolean(b)
  358. int b;
  359. {
  360.   MidasOperand Temp;
  361.   Temp.Type = MBoolean;
  362.   Temp.Dynamic = FALSE;
  363.   Temp.Value.I = (b != 0);
  364.   return Temp;
  365.  
  366. }
  367.